package com.example.nio.network.reactor;

import java.io.Closeable;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.util.Iterator;
import java.util.Set;

/**
 * @author panghu
 * @version 1.0.0
 * @createTime 2023年08月07日 20:47:00
 * @Description
 */
public class Reactor implements Closeable,Runnable {

    private final ServerSocketChannel serverChannel;
    private final Selector selector;

    public Reactor() throws IOException {
        this.serverChannel = ServerSocketChannel.open();
        this.selector = Selector.open();
    }

    @Override
    public void run() {
         try {
             // 给serverChannel绑定端口
             serverChannel.bind(new InetSocketAddress(9000));
             // 要使用选择器进行操作，就必须设置为accept非阻塞的方式，这样的话才能实现改高效利用
             serverChannel.configureBlocking(false);
             // 注册时，将Acceptor作为附加对象存放，当选择器选择后也可以获取到
             serverChannel.register(selector, SelectionKey.OP_ACCEPT,new Acceptor(serverChannel,selector));
             while (true){
                 int count = selector.select();
                 System.out.println("监听到 "+count+" 个事件");
                 Set<SelectionKey> selectionKeys = selector.selectedKeys();
                 Iterator<SelectionKey> iterator = selectionKeys.iterator();
                 while (iterator.hasNext()){
                     this.dispatch(iterator.next()); // 通过dispatch方法进行分发
                     iterator.remove();
                 }
             }
         }catch (IOException ex){
             ex.printStackTrace();
         }
    }

    /**
     * 通过此方法进行分发连接对象
     * @param key
     */
    private void dispatch(SelectionKey key){
        Object att = key.attachment(); // 获取attachment, ServerSocketChannel和对应的客户端Channel都一起拿到了
        if (att instanceof Runnable){
            ((Runnable)att).run(); // 由于Handler和Acceptor都实现自Runnable接口，这里就统一调用一下
            // 这样就实现了对应的时候调用对应的Handler或是Acceptor了
        }
    }

    /**
     * 用了记得关，保持好习惯
     * @throws IOException
     */
    @Override
    public void close() throws IOException {
         serverChannel.close();
         selector.close();
    }
}
